//
//  iCanViewController.m
//  iCan - iPhone Context-Aware Navigation
//  Carnegie Mellon University - 18-842 Distributed Systems
//
//  Created by Andrew Santell on 3/26/12.
//  Copyright (c) 2012 Andrew Santell. All rights reserved.


/* Root View Controller.  Prompts user with initial login */

#import "iCanViewController.h"
#import "iCanAppDelegate.h"
#import "Hosts.h"
#import "NSDataEncryption.h"
#import "Base64.h"

@implementation iCanViewController
@synthesize passText, userText;
@synthesize message, result;
@synthesize inputStream, outputStream;
@synthesize appDelegate;

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
}

#pragma mark - View lifecycle

- (void)viewDidLoad
{
    [super viewDidLoad];
    appDelegate = [[UIApplication sharedApplication] delegate];
    appDelegate.nodePort = 12345; //Setting global port for nodes
    appDelegate.authPort = 23456; //Setting global port for Auth Server
    //appDelegate.authIP = @"128.237.225.68"; //Setting global IP for Auth Server
    //appDelegate.authIP = @"128.237.253.18";
    appDelegate.authIP = @"128.237.242.167";
}

- (void)viewDidUnload
{
    [self setPassText:nil];
    [self setUserText:nil];
    [super viewDidUnload];
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
}

- (void)viewWillDisappear:(BOOL)animated
{
	[super viewWillDisappear:animated];
}

- (void)viewDidDisappear:(BOOL)animated
{
	[super viewDidDisappear:animated];
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    // Return YES for supported orientations
    return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}

- (IBAction)login:(id)sender 
{        
    /* Bounds checking on User Input */
    NSCharacterSet *charSet = [NSCharacterSet alphanumericCharacterSet];
    BOOL validUser = [[userText.text stringByTrimmingCharactersInSet:charSet] isEqualToString:@""];
    BOOL validPass = [[passText.text stringByTrimmingCharactersInSet:charSet] isEqualToString:@""];
    
    UIAlertView *invalidChar = [[UIAlertView alloc] initWithTitle:@"Error" message:@"You have entered invalid data. Please try again."delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
    
    if ((validUser == FALSE) || (userText.text.length > 20) || (userText.text.length == 0))
    {
        [invalidChar show];
    }   
    else if ((validPass == FALSE) || (passText.text.length > 20) || (passText.text.length == 0))
    {
        [invalidChar show];
    }
    else 
    {
        NSString *sanitizedPassword = [passText.text stringByReplacingOccurrencesOfString:@";" withString:@"%42"];
        
        /* Build network message */
        message = userText.text;
        message = [message stringByAppendingString:@";"];
        message = [message stringByAppendingString:sanitizedPassword];
        message = [message stringByAppendingString:@";"];
        message = [message stringByAppendingString:@"\n"];
        [self initNetworkCommunication]; 
    }
}

- (void) analyzeResult
{
 	/* Set up alert for errors */
    UIAlertView *invalidAlert = [[UIAlertView alloc] initWithTitle:@"Authentication Error" message:@"Your user name or password is incorrect."delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
    UIAlertView *badAlert = [[UIAlertView alloc] initWithTitle:@"Authentication Error" message:@"An error has occured.  Please try again."delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
    
    /* The server responds ACK on success and NACK on error */
    NSLog(@"result = %@", result);
    
    if ([result isEqualToString:@"INVALID"])
    {
        [invalidAlert show];
    }
    else if ([result isEqualToString:@"NACK"])
    {
        [badAlert show];
    }
    else 
    {
        NSLog(@"result = %@", result);
        
        NSArray *totalArray = [result componentsSeparatedByString:@"%"];
        appDelegate.myCookie = [totalArray objectAtIndex:0]; //Parsing out cookie from return
        appDelegate.myName = userText.text; //Setting global userName from login screen
        
        int arrayLength = ([totalArray count]) - 1;
        int hostCount = 1;
        
        appDelegate.nodes = [[NSMutableDictionary dictionary] init];
        Hosts *host = [[Hosts alloc] init];
        
        
        while (hostCount < arrayLength)
        {
            NSArray *tempArray = [[totalArray objectAtIndex:hostCount] componentsSeparatedByString:@";"];
            NSLog(@"temparray = %@", tempArray);
            host.name = [tempArray objectAtIndex:0];
            host.ip = [tempArray objectAtIndex:1];
            host.port = (UInt32)[tempArray objectAtIndex:2];
  
            [appDelegate.nodes setObject:host forKey:host.name];
            host = [[Hosts alloc] init];
            hostCount++;
        }
        
        
       /* for (NSString* nameIter in appDelegate.nodes)
        {
            NSLog(@"Host key = %@", nameIter);
            NSLog(@"Host value = %@", [[appDelegate.nodes valueForKey:nameIter] string]);
        } */
        
        result = NULL;
        NSLog(@"Hosts = %d", [appDelegate.nodes count]);
        [self performSegueWithIdentifier:@"login" sender:self];
    }
      
    
}

/* Initiate network connection */
- (void) initNetworkCommunication
{
    
    CFReadStreamRef readStream = NULL;
    CFWriteStreamRef writeStream = NULL;
    CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)appDelegate.authIP, appDelegate.authPort, &readStream, &writeStream);
    
    inputStream = (__bridge NSInputStream *) readStream;
    outputStream = (__bridge NSOutputStream *) writeStream;
    
    [inputStream setDelegate:self];
    [outputStream setDelegate:self];
    
    /* Put input and output streams into a run loop */
    [inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    [outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    
    [inputStream open];
    [outputStream open];
    
    /* Encode data before sending across wire */

    NSData *data = [[NSData alloc] initWithData:[message dataUsingEncoding:NSASCIIStringEncoding]];
    NSString *b64;
    Base64 *b64Obj = [[Base64 alloc] init];
    b64 = [b64Obj Base64Encode:data];
    
    /* Add function name to beginning of base64 so it is sent in clear.  Convert to data before sending over wire*/
    NSString *sendString = [@"login;" stringByAppendingString:b64];
    NSData *sendData = [[NSData alloc] initWithData:[sendString dataUsingEncoding:NSASCIIStringEncoding]];
    
    /* Send message to network */
    [outputStream write:[sendData bytes] maxLength:[sendData length]];
}

- (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent 
{
    /* Create error popup for failed connections */
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" message:@"Could not connect to host"delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
    
    switch (streamEvent) 
    {
		case NSStreamEventOpenCompleted:
			NSLog(@"Stream opened");
			break;
            
        /* Accept return message from network */
		case NSStreamEventHasBytesAvailable:
            
            if (theStream == inputStream) 
            {
                
                uint8_t buffer[1024];
                int len;
                
                while ([inputStream hasBytesAvailable]) 
                {
                    len = [inputStream read:buffer maxLength:sizeof(buffer)];
                    if (len > 0) 
                    {
                        
                        result = [[NSString alloc] initWithBytes:buffer length:len encoding:NSASCIIStringEncoding];
                        
                        if (nil != result) 
                        {
                            NSLog(@"Response: %@", result);
                            [self analyzeResult];
                        }
                    }
                }
            }
			break;			
            
		case NSStreamEventErrorOccurred:
            NSLog(@"Can not connect to the host!");
            NSLog(@"Error Result (Should be NULL) = %@", result);
            [inputStream close];
            [inputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
            [outputStream close];
            [outputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
            [alert show];
			break;
            
		case NSStreamEventEndEncountered:
            NSLog(@"Closing Connection");
            [inputStream close];
            [inputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
            [outputStream close];
            [outputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
			break;
            
		case NSStreamEventHasSpaceAvailable:
            NSLog (@"Output Buffer is Empty");
            break;
            
        default:
			NSLog(@"Unknown event");
            NSLog(@"Error Result (Should be NULL) = %@", result);
            [inputStream close];
            [inputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
            [outputStream close];
            [outputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
            [alert show];
	}
}


- (BOOL)textFieldShouldReturn:(UITextField *)theTextField 
{
     if (theTextField == self.userText) {
    [theTextField resignFirstResponder];
     }
    if (theTextField == self.passText) {
        [theTextField resignFirstResponder];
    }
    return YES;
}
@end
